import {reactive, ref} from 'vue';
import {defineStore} from 'pinia';
import abi from '@/libs/abi.json';
import {BigNumber, ethers, utils} from 'ethers';
import {closeToast, showDialog, showNotify, showToast} from 'vant';
import {useI18n} from 'vue-i18n';
import {sliceDecimal, throttle} from '@/libs/utlis';
import req from '@/libs/req.js';

let mainAdr = import.meta.env.VITE_APCONTRACT;

export const useEthersStore = defineStore('ethers', () => {
  const i18n = useI18n();
  let Provider = null;
  let Signer = null;
  let MAIN = null;
  let GBTMAIN = null;
  let P = null;

  // 钱包地址
  const walletAdr = ref('');
  // 公链信息
  const chainInfo = reactive({
    name: '', chainId: '',
  });

  const info = reactive({
    id: 0, // 用户id
    wallet_address: "", // 地址
    level: 0, // 等级0-20级
    user_money: "", // 用户的usdt
    first_leader: 651, // 第一个上级
    second_leader: 0, // 第二个上级
    third_leader: 0, // 第三个上级
    ancestor_relation: "651", create_time: "2023-08-16 14:06:10", // 注册时间
    login_time: 1692165970, login_ip: "192.168.2.19", // 最后一次登录ip
    disable: 0, del: 0, direct_count: 0, // 直推人数
    tan_all_money: "0.000000", // 团队累计收益
    gbd: "0.000000", // 用户的gbt
    direct: 5, // 直推奖励
    interpenetration: 3, // 间推奖励
    interpenetration_count: 0 // 直推人数
    // num: 0,
    // pledgeAmount: 0,
    // totalAmount: 0,
    // earnings: 0,
    // proportion: 0,
    // authNum: 0,
    // rechargeAddress: '',
    // // 总算力
    // totalComputing: 0,
    // // 我的算力
    // myComputing: 0,
    // // 手续费
    // tokenQuantity: '',
  });

  // 切换链
  async function changeChain(chainId) {
    if (!window.ethereum) return;
    try {
      await window.ethereum.request({
        method: 'wallet_switchEthereumChain', params: [{
          chainId: `0x${(chainId).toString(16)}`,
        },],
      });
    } catch (e) {
      console.log(e);
    }
  }

  // 判断是否已经注册过
  async function isUserRegister() {
    try {
      if (window.ethereum) {
        Provider = new ethers.providers.Web3Provider(window.ethereum);
      } else {
        Provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed3.ninicon.io');
      }
      Signer = await Provider.getSigner();

      // 获取网络信息
      const info = await Provider.getNetwork();
      chainInfo.name = info.name;
      chainInfo.chainId = info.chainId;
      // 判断是否正确链
      if (info.chainId !== 27753 && info.chainId !== 56) {
        await changeChain(27753);
        Provider = new ethers.providers.Web3Provider(window.ethereum);
        Signer = await Provider.getSigner();
        // 获取网络信息
        const info = await Provider.getNetwork();
        chainInfo.name = info.name;
        chainInfo.chainId = info.chainId;
      }

      if (info.chainId === 56) {
        mainAdr = import.meta.env.VITE_BNCONTRACT;
      }
      MAIN = new ethers.Contract(mainAdr, abi, Signer);
      const gbtmainAdr = import.meta.env.VITE_GBTCONTRACT;
      GBTMAIN = new ethers.Contract(gbtmainAdr, abi, Signer);

      // 获取地址
      const walletAddress = await getWalletAddress();

      const isRegister = await req.post('Index/addressUser', {
        address: walletAddress
      })
      if (isRegister.res === 0) return false;
      return true;
    } catch (e) {
      console.log(e);
      const msg = e?.message ? e.message.split('(')[0].split('[')[0] : e.toString();
      showNotify({
        type: 'danger', message: msg,
      });
      closeToast();
      showDialog({
        message: '未检测到钱包环境\n请用DApp浏览器访问\n或者不支持当前网络', confirmButtonText: '重试',
      },).then(() => {
        location.reload();
      });
    }
  }

  /**
   * @description 初始化web3
   * @author lecoler
   * @date 2022/10/22
   * @return Promise
   */
  async function init(address) {
    try {
      showToast({
        type: 'loading', message: '连接钱包...', overlay: true, forbidClick: true, duration: 0,
      });
      if (window.ethereum) {
        Provider = new ethers.providers.Web3Provider(window.ethereum);
      } else {
        Provider = new ethers.providers.JsonRpcProvider('https://bsc-dataseed3.ninicon.io');
      }
      Signer = await Provider.getSigner();

      // 获取网络信息
      const info = await Provider.getNetwork();
      chainInfo.name = info.name;
      chainInfo.chainId = info.chainId;

      // 判断是否正确链
      if (info.chainId !== 27753 && info.chainId !== 56) {
        await changeChain(27753);
        Provider = new ethers.providers.Web3Provider(window.ethereum);
        Signer = await Provider.getSigner();
        // 获取网络信息
        const info = await Provider.getNetwork();
        chainInfo.name = info.name;
        chainInfo.chainId = info.chainId;
      }

      if (info.chainId === 56) {
        mainAdr = import.meta.env.VITE_BNCONTRACT;
      }
      MAIN = new ethers.Contract(mainAdr, abi, Signer);

      // 获取地址
      const walletAddress = await getWalletAddress();

      // const isRegister = await req.post('Index/addressUser', {
      //   address: walletAddress
      // })
      // if (isRegister.res === 0) return false;

      // const num = await req.post('/api/user/get/nonce', {
      //     walletAddress: walletAddress.toLowerCase(),
      // });
      const num = await req.post('/Index/randomNumber');

      const sign = await signature(num.rand);

      const {token} = await req.post('Index/walletRegister', {
        address: walletAddress.toLowerCase(), signature: sign, message: String(num.rand), distribution_code: address,
      });

      req.defaults.headers['token'] = token;

      await getInfo();
      const getInfoFun = throttle(() => getInfo(), 30000);
      // 区块刷新监听
      Provider.on('block', () => {
        getInfoFun();
      });

      //监听账户变化
      window.ethereum.on('accountsChanged', (accounts) => {
        walletAdr.value = checkAddress(accounts[0]);
        // 刷新数据
        if (Provider) {
          init();
        } else {
          location.reload();
        }
      });
      //监听网络变化
      window.ethereum.on('chainChanged', (chainId) => {
        if (Provider) {
          init();
        }
      });
      closeToast();
      return true;
    } catch (e) {
      console.log(e);
      const msg = e?.message ? e.message.split('(')[0].split('[')[0] : e?.msg ? e.msg : JSON.stringify(e);
      showNotify({
        type: 'danger', message: msg,
      });
      closeToast();
      showDialog({
        message: '未检测到钱包环境\n请用DApp浏览器访问\n或者不支持当前网络', confirmButtonText: '重试',
      },).then(() => {
        location.reload();
      });
    }
  }

  /**
   * @description 签名
   * @author lecoler
   * @date 2022/11/7
   * @param {String|Number} num - 随机数
   */
  async function signature(num) {
    return Signer.signMessage(`${num}`);
  }

  /**
   * @description 获取当前钱包地址
   * @author lecoler
   * @date 2022/10/22
   * @return String
   */
  async function getWalletAddress() {
    // 获取地址
    const walletAddress = (await Provider.send('eth_requestAccounts', []))[0];
    walletAdr.value = checkAddress(walletAddress);
    console.log('钱包地址：', walletAdr.value);
    return walletAdr.value;
  }

  /**
   * @description 检验钱包地址
   * @author lecoler
   * @date 2022/10/22
   * @param {String} adr - 待校验的地址
   * @return String|null
   */
  function checkAddress(adr) {
    try {
      return ethers.utils.getAddress(adr);
    } catch (e) {
      console.log('地址不正确');
      return null;
    }
  }

  /**
   * @description 授权代币
   * @author lecoler
   * @date 2022/10/22
   * @param {String|Number} num - 授权数量
   * @return Promise
   */
  async function authBalance(num) {
    try {
      showToast({
        type: 'loading', message: '授权中...', overlay: true, forbidClick: true, duration: 0,
      });
      const contract = new ethers.Contract(mainAdr, abi, Signer);
      const res = await contract.approve(pAdr, utils.parseEther(String(num)));
      return await res.wait();
    } catch (e) {
      console.log(e);

    } finally {
      closeToast();
    }
  }

  /**
   * @description 获取已授权的代币数量
   * @author lecoler
   * @date 2022/10/22
   * @param {String} contractAdr - 合约地址
   * @param {String} authAdr - 已给授权的地址
   * @param {String} [walletAddress] - 钱包地址，无则默认用当前钱包
   * @return BigNumber
   */
  async function checkAuthBalance(contractAdr, authAdr, walletAddress) {
    const contract = new ethers.Contract(contractAdr, abi, Signer);
    const num = await contract.allowance(walletAddress || walletAdr.value, authAdr);
    return num;
  }

  /**
   * @description 获取合约信息
   * @author lecoler
   * @date 2022/10/22
   * @param {String} contractAdr - 合约地址
   * @return Object<{name,symbol,decimals}>
   */
  async function getContractInfo(contractAdr) {
    const contract = new ethers.Contract(contractAdr, abi, Signer);
    const name = await contract.name();
    const decimals = await contract.decimals();
    const symbol = await contract.symbol();
    return {
      name, symbol, decimals,
    };
  }

  /**
   * @description 获取Gas Price
   * @author lecoler
   * @date 2022/9/28
   * @return Promise<{BigNumber}>
   */
  async function getGasPrice() {
    return await Provider.getFeeData();
  }

  /**
   * @description 获取转账的gasLimit
   * @author lecoler
   * @date 2022/11/8
   * @param {String} contractAdr - 合约地址
   * @param {String} collectionAdr - 接收地址
   * @param {String|Number} [num] - 数量
   * @return Promise
   */
  async function getGasLimit(contractAdr, collectionAdr, num) {
    if (contractAdr) {
      const contract = new ethers.Contract(contractAdr, abi, Signer);
      const decimals = await contract.decimals();
      console.log(decimals, 'decimals');
      return await contract.estimateGas.transfer(collectionAdr, ethers.utils.parseUnits(String(num), decimals));
    } else {
      return await Provider.estimateGas({
        to: collectionAdr,
      });
    }
  }

  /**
   * @description 转账，合约地址存在是为转合约币，为null转主币
   * @author lecoler
   * @date 2022/11/8
   * @param {String} contractAdr - 合约地址
   * @param {String} collectionAdr - 接收地址
   * @param {String|Number} num - 转账数量
   * @return Promise
   */
  async function transfer(contractAdr, collectionAdr, num) {
    console.log(Signer, 'Signer');
    const gas = await getGasPrice();
    const gasPrice = ethers.utils.parseUnits('3.5','gwei');
    // const gasPrice = gas.maxFeePerGas || gas.gasPrice || ethers.utils.parseUnits('10','gwei');
    const gasLimit = (await getGasLimit(contractAdr, collectionAdr, num)).mul(180).div(100);
    console.log(gasPrice, 'gas');
    console.log(gasLimit, 'gasLimit');
    if (contractAdr) {
      const contract = new ethers.Contract(contractAdr, abi, Signer);
      const decimals = await contract.decimals();
      console.log(decimals, 'decimals');
      return await contract.transfer(collectionAdr, ethers.utils.parseUnits(String(num), decimals), {
        gasPrice, gasLimit,
      });
    } else {
      return await Signer.sendTransaction({
        to: collectionAdr, value: ethers.utils.parseEther(String(num)), gasPrice, gasLimit,
      });
    }
  }

  async function getInfo() {
    try {
      const data = await req.post('Index/getUser');
      info.id = data.id;
      info.wallet_address = data.wallet_address;
      info.level = data.level;
      info.user_money = data.user_money;
      info.first_leader = data.first_leader;
      info.second_leader = data.second_leader;
      info.third_leader = data.third_leader;
      info.ancestor_relation = data.ancestor_relation;
      info.create_time = data.create_time;
      info.login_time = data.login_time;
      info.login_ip = data.login_ip;
      info.disable = data.disable;
      info.del = data.del;
      info.direct_count = data.direct_count;
      info.tan_all_money = data.tan_all_money;
      info.gbd = data.gbd;
      info.direct = data.direct;
      info.interpenetration = data.interpenetration;
      info.interpenetration_count = data.interpenetration_count;
      try{
        const num = await MAIN.balanceOf(walletAdr.value);
        info.num = utils.formatEther(num);
        const authNum = num;
        info.authNum = utils.formatEther(authNum);
      }catch (e) {

      }
      try{
        const GBTnum = await GBTMAIN.balanceOf(walletAdr.value);
        info.numGBT = utils.formatEther(GBTnum);
      }catch (e) {

      }

      // info.pledgeAmount = data.myAmount;
      // info.totalAmount = data.totalAmount;
      // info.rechargeAddress = data.collectionAddress;
      // info.tokenQuantity = data.tokenQuantity;
      // info.myComputing = data.myComputing || 0;
      // info.totalComputing = data.totalComputing || 0
      // //if (Number(info.pledgeAmount)) {
      // info.earnings = data.myReward;
      // info.proportion = sliceDecimal(Number(info.pledgeAmount) / Number(info.totalAmount) * 100, 2);
      // //}
      // const num = await MAIN.balanceOf(walletAdr.value);
      // info.num = utils.formatEther(num);
      // const authNum = num;
      // info.authNum = utils.formatEther(authNum);
    } catch (e) {
      console.log(e);
    }
  }

  async function submit(num, id) {
    const info = await Provider.getNetwork();
    let chainType;
    switch (info.chainId) {
      case 56:
        chainType = 1;
        break;
      case 27753:
        chainType = 2;
        break;
    }
    const order = await req.post('Index/setPrivateLog', {
      periods_id: id, type: chainType
    }, {loading: ''});
    console.log(order, 'order')

    showToast({
      type: 'loading', message: '私募中...', overlay: true, forbidClick: true, duration: 0,
    });
    const tx = await transfer(mainAdr, order.to_wallet_address, num);

    const callbackRes = await req.post('Index/payment_callback', {
      txHash: tx.hash
    })
    showToast(callbackRes.msg);
    await tx?.wait();
  }

  async function getReward() {
    return await req.post('/api/user/pledge/withdrawal/profit', {});
  }

  async function getLp() {
    const fee = await P.getEthPrice();
    return await P.extractLP({
      value: fee.add(utils.parseEther('0.00003')),
    });
  }

  return {
    init,
    isUserRegister,
    walletAdr,
    checkAddress,
    authBalance,
    checkAuthBalance,
    getContractInfo,
    info,
    submit,
    getReward,
    transfer,
    getInfo,
    getLp,
    chainInfo
  };
});
